//
// Description: 匈牙利算法 模板
// Created by Loading on 2022/5/22.
//

/*
 * 适用于求一个二分图中的最大匹配次数
 * 二分图的最大匹配次数：指一个二分图的两个点的集合中最多可以连接多少条边（每个节点只能使用一次）
 */

/*
 * 算法思想：遍历其中一个集合的每个点的每条边，匹配端点，发现目标端点匹配过时，查看它匹配的端点可否更换
 * 从第一个点开始遍历，遍历其每条边，查看边的另一个端点是否匹配
 * 1、若未匹配，则直接匹配成功
 * 2、若已匹配，则递归判断它匹配的那个点是否可以更换匹配
 * 若可以更换，则匹配成功；若所有边均尝试且均无法更换，则匹配失败。
 */

#include <bits/stdc++.h>

using namespace std;

constexpr int N = 510, M = 1e5 + 10;

// 左半部的点的个数
int n1;
// 邻接表
int h[N], e[M], ne[M], idx;
// 表示右半部匹配到的左半部的点的编号，0 表示未匹配
int match[N];
// 表示右半部中的点是否已经遍历过
bool st[N];

/* 时间复杂度：O(nm)，n 表示点数，m 表示边数 */
// 返回能否找到与 x 匹配的点
bool Hungarian(int x) {
    for (int i = h[x]; i != -1; i = ne[i]) {
        int j = e[i];
        if (!st[j]) {
            st[j] = true;
            // 右半部点未匹配或已匹配到的左半部的点可以重新找一个点匹配，则当前点匹配成功
            if (!match[j] || Hungarian(match[j])) {
                /* 注意：不要写成 match[x] = j */
                match[j] = x;
                return true;
            }
        }
    }

    // 所有点均匹配失败
    return false;
}

int main() {
    // 省略输入

    // 求最大匹配数，依次枚举第一个集合中的每个点能否匹配第二个集合中的点
    int res = 0;
    for (int i = 1; i <= n1; ++i) {
        // 每次寻找，都要重置st数组
        memset(st, false, sizeof st);
        if (Hungarian(i)) {
            ++res;
        }
    }

    return 0;
}